using EOSDigital.SDK;
using System;
using System.Collections.Generic;
using System.Drawing;
using System.Drawing.Imaging;
using System.Linq;
using System.Threading;

namespace EOSDigital.API
{
	public class CanonAPI : IDisposable
	{
		protected static SDKCameraAddedHandler CameraAddedEvent;

		protected static STAThread MainThread;

		private static bool _IsSDKInitialized;

		private bool IsDisposed;

		private static int RefCount = 0;

		private static readonly object InitLock = new object();

		private static List<Camera> CurrentCameras = new List<Camera>();

		private static readonly object CameraLock = new object();

		public static bool IsSDKInitialized
		{
			get
			{
				return CanonAPI._IsSDKInitialized;
			}
		}

		public event CameraAddedHandler CameraAdded;

		private ErrorCode CanonAPI_CameraAddedEvent(IntPtr inContext)
		{
			if (this.CameraAdded != null)
			{
				this.CameraAdded(this);
			}
			return ErrorCode.OK;
		}

		public CanonAPI()
			: this(false)
		{
		}

		public CanonAPI(bool useCallingThread)
		{
			try
			{
				lock (CanonAPI.InitLock)
				{
					if (CanonAPI.RefCount == 0)
					{
						if (useCallingThread)
						{
							if (Thread.CurrentThread.GetApartmentState() != 0)
							{
								throw new ThreadStateException("Calling thread must be in STA");
							}
							ErrorHandler.CheckError(this, CanonSDK.EdsInitializeSDK());
						}
						else
						{
							CanonSDK.EdsRelease(IntPtr.Zero);
							CanonAPI.MainThread = new ApiThread();
							CanonAPI.MainThread.Start();
							CanonAPI.MainThread.Invoke(delegate
							{
								ErrorHandler.CheckError(this, CanonSDK.EdsInitializeSDK());
							});
						}
						CanonSDK.InitializeVersion();
						CanonAPI.CameraAddedEvent = this.CanonAPI_CameraAddedEvent;
						ErrorHandler.CheckError(this, CanonSDK.EdsSetCameraAddedHandler(CanonAPI.CameraAddedEvent, IntPtr.Zero));
						CanonAPI._IsSDKInitialized = true;
					}
					CanonAPI.RefCount++;
				}
			}
			catch
			{
				this.IsDisposed = true;
				if (CanonAPI.MainThread != null && CanonAPI.MainThread.IsRunning)
				{
					CanonAPI.MainThread.Shutdown();
				}
				throw;
			}
		}

		~CanonAPI()
		{
			this.Dispose(false);
		}

		public void Dispose()
		{
			this.Dispose(true);
			GC.SuppressFinalize(this);
		}

		protected virtual void Dispose(bool managed)
		{
			lock (CanonAPI.InitLock)
			{
				if (!this.IsDisposed)
				{
					if (CanonAPI.RefCount == 1)
					{
						ErrorCode errorCode = CanonSDK.EdsSetCameraAddedHandler(null, IntPtr.Zero);
						if (managed)
						{
							ErrorHandler.CheckError(this, errorCode);
							CanonAPI.CurrentCameras.ForEach(delegate(Camera t)
							{
								t.Dispose();
							});
						}
						if (CanonAPI.MainThread != null && CanonAPI.MainThread.IsRunning)
						{
							errorCode = CanonAPI.MainThread.Invoke(() => CanonSDK.EdsTerminateSDK());
						}
						if (CanonAPI.MainThread != null && CanonAPI.MainThread.IsRunning)
						{
							CanonAPI.MainThread.Shutdown();
						}
						if (managed)
						{
							ErrorHandler.CheckError(this, errorCode);
						}
					}
					CanonAPI.RefCount--;
					this.IsDisposed = true;
                    CanonAPI._IsSDKInitialized = false;
                }
			}
		}

		public List<Camera> GetCameraList()
		{
			if (this.IsDisposed)
			{
				throw new ObjectDisposedException("CanonAPI");
			}
			lock (CanonAPI.CameraLock)
			{
				IEnumerable<IntPtr> ptrList = this.GetCameraPointerList();
				List<Camera> list = new List<Camera>();
				foreach (IntPtr item in ptrList)
				{
					List<Camera> currentCameras = CanonAPI.CurrentCameras;
					Func<Camera, bool> predicate = (Camera t) => t.Reference == item;
					Camera camera = currentCameras.FirstOrDefault(predicate);
					if (camera != null && !camera.IsDisposed)
					{
						list.Add(camera);
					}
					else
					{
						list.Add(new Camera(item));
					}
				}
				IEnumerable<Camera> enumerable = from t in CanonAPI.CurrentCameras
				where !ptrList.Any((IntPtr u) => u == t.Reference)
				select t;
				foreach (Camera item2 in enumerable)
				{
					if (!item2.IsDisposed)
					{
						item2.Dispose();
					}
				}
				CanonAPI.CurrentCameras.Clear();
				CanonAPI.CurrentCameras.AddRange(list);
				return list;
			}
		}

		protected IEnumerable<IntPtr> GetCameraPointerList()
		{
			if (this.IsDisposed)
			{
				throw new ObjectDisposedException("CanonAPI");
			}
			IntPtr inRef = default(IntPtr);
			ErrorHandler.CheckError(this, CanonSDK.EdsGetCameraList(out inRef));
			int num = default(int);
			ErrorHandler.CheckError(this, CanonSDK.EdsGetChildCount(inRef, out num));
			List<IntPtr> list = new List<IntPtr>();
			for (int i = 0; i < num; i++)
			{
				IntPtr item = default(IntPtr);
				ErrorHandler.CheckError(this, CanonSDK.EdsGetChildAtIndex(inRef, i, out item));
				list.Add(item);
			}
			ErrorHandler.CheckError(this, CanonSDK.EdsRelease(inRef));
			return list;
		}

		public Bitmap GetFileThumb(string filepath)
		{
			using (SDKStream sDKStream = new SDKStream(filepath, FileCreateDisposition.OpenExisting, FileAccess.Read))
			{
				return this.GetImage(sDKStream.Reference, ImageSource.Thumbnail);
			}
		}

		protected unsafe Bitmap GetImage(IntPtr imgStream, ImageSource imageSource)
		{
			IntPtr zero = IntPtr.Zero;
			IntPtr zero2 = IntPtr.Zero;
			try
			{
				ErrorHandler.CheckError(this, CanonSDK.EdsCreateImageRef(imgStream, out zero));
				ImageInfo imageInfo = default(ImageInfo);
				ErrorHandler.CheckError(this, CanonSDK.EdsGetImageInfo(zero, imageSource, out imageInfo));
				EOSDigital.SDK.Size inDstSize = default(EOSDigital.SDK.Size);
				inDstSize.Width = imageInfo.EffectiveRect.Width;
				inDstSize.Height = imageInfo.EffectiveRect.Height;
				int num = inDstSize.Height * inDstSize.Width * 3;
				byte[] array = new byte[num];
				using (SDKStream sDKStream = new SDKStream(array))
				{
					ErrorHandler.CheckError(this, CanonSDK.EdsGetImage(zero, imageSource, TargetImageType.RGB, imageInfo.EffectiveRect, inDstSize, sDKStream.Reference));
					try
					{
						byte[] array2 = array;
						fixed (byte* ptr = array2)
						{
							for (long num2 = 0L; num2 < num; num2 += 3)
							{
								byte b = ptr[num2];
								ptr[num2] = ptr[num2 + 2];
								ptr[num2 + 2] = b;
							}
						}
					}
					finally
					{
					}
					ErrorHandler.CheckError(this, CanonSDK.EdsGetPointer(sDKStream.Reference, out zero2));
					return new Bitmap(inDstSize.Width, inDstSize.Height, num, PixelFormat.Format24bppRgb, zero2);
				}
			}
			finally
			{
				if (imgStream != IntPtr.Zero)
				{
					ErrorHandler.CheckError(this, CanonSDK.EdsRelease(imgStream));
				}
				if (zero != IntPtr.Zero)
				{
					ErrorHandler.CheckError(this, CanonSDK.EdsRelease(zero));
				}
			}
		}
	}
}
